﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Xml;
using Assist;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.ExtensibleStorage;
using Autodesk.Revit.DB.Plumbing;
using Autodesk.Revit.UI;
using YArchitech.Controls;
using YArchitech.LIB;
using YArchitech.Revit.MEP.Opening.Common;
using YArchitech.Revit.RevitExtension;
using HYView;

namespace YArchitech.Revit.MEP.Opening
{
	[Transaction(TransactionMode.Manual)]
	[Regeneration(RegenerationOption.Manual)]
	public class CmdDrivepipeAdd : IExternalCommand
	{
		[DllImport("user32.dll", EntryPoint = "SendMessageA")]
		public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

		public Result Execute(ExternalCommandData cmdData, ref string msg, ElementSet elems)
		{
			try
			{
				CmdViewType types = (CmdViewType)3;
				if (SwitchView.SetUsableView(types, cmdData) != Autodesk.Revit.UI.Result.Succeeded)
				{
					return Autodesk.Revit.UI.Result.Failed;
				}
				string strXmlFilePath = ConfigDataOperate.InitConfigDataFile();
				this.m_dimConfig = new ConfigDataOperate.OfferConfigData(strXmlFilePath);
				this.m_xmlDoc = new XmlDocument();
				this.m_xmlDoc.Load(Product.DataLocation + "\\DrivepipeData.xml");
				WindowHandle windowHandle = new WindowHandle(Process.GetCurrentProcess().MainWindowHandle);
				DlgAddDrivepipe dlgAddDrivepipe = new DlgAddDrivepipe(windowHandle);
				dlgAddDrivepipe.Show(windowHandle);
				int wMsg = 7;
				CmdDrivepipeAdd.SendMessage(windowHandle.Handle, wMsg, IntPtr.Zero, IntPtr.Zero);
				UIDocument activeUIDocument = cmdData.Application.ActiveUIDocument;
				this.SearchAllDrivepipe(activeUIDocument.Document);
				List<Pipe> list = new List<Pipe>();
				for (;;)
				{
					if (this.SelectPipe(activeUIDocument, dlgAddDrivepipe.SelPipeType, list))
					{
						this.AddDrivepipe(cmdData.Application, dlgAddDrivepipe.DrivepipeType, list);
					}
					else
					{
						if (!dlgAddDrivepipe.SelPipeTypeChange)
						{
							break;
						}
						dlgAddDrivepipe.SelPipeTypeChange = false;
					}
				}
				dlgAddDrivepipe.Close();
			}
			catch (Exception ex)
			{
				YJKMessageBox.Show(ex.Message);
				return Autodesk.Revit.UI.Result.Failed;
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private void SearchAllDrivepipe(Autodesk.Revit.DB.Document doc)
		{
			this.m_lstAllDrivepipe = new List<FamilyInstance>();
			foreach (Element element in YJKElementFilter.GetElementByClass(typeof(FamilyInstance), doc))
			{
				FamilyInstance familyInstance = element as FamilyInstance;
				if (this.ReadPipeIdFromXData(familyInstance) != null)
				{
					this.m_lstAllDrivepipe.Add(familyInstance);
				}
			}
		}

		private bool SelectPipe(UIDocument UIDoc, int nSelType, List<Pipe> lstSelPipe)
		{
			try
			{
				lstSelPipe.Clear();
				PipeFilter pipeFilter = new PipeFilter();
				if (nSelType == 0)
				{
					Reference reference = UIDoc.Selection.PickObject((Autodesk.Revit.UI.Selection.ObjectType)1, pipeFilter, "请选择一条垂直穿墙水平水管");
					Element element = UIDoc.Document.GetElement(reference);
					lstSelPipe.Add(element as Pipe);
				}
				else
				{
					foreach (Element element2 in UIDoc.Selection.PickElementsByRectangle(pipeFilter, "请框选垂直穿墙水平水管"))
					{
						lstSelPipe.Add(element2 as Pipe);
					}
				}
			}
			catch
			{
				return false;
			}
			return true;
		}

		private void AddDrivepipe(UIApplication uiApp, int nDrivepipeType, List<Pipe> lstPipe)
		{
			string drivepipeFamilyName = this.GetDrivepipeFamilyName(nDrivepipeType);
			this.m_Drivepipe = this.LoadFamily(uiApp, drivepipeFamilyName);
			if (this.m_Drivepipe == null)
			{
				return;
			}
			int num = 0;
			List<LinkFile> linkFiles = LinkFile.GetLinkFiles(uiApp.ActiveUIDocument.Document);
			foreach (Pipe pipe in lstPipe)
			{
				Line curve = CmdTools.FindPipeLine(pipe);
				curve.GetEndPoint(0);
				curve.GetEndPoint(1);
				int num2 = (int)AssistFunc.feetToMM(pipe.Diameter);
				string drivepipeDimMark = this.GetDrivepipeDimMark(drivepipeFamilyName, num2);
				if (drivepipeDimMark == null)
				{
					if (lstPipe.Count == 1)
					{
						string str = string.Format("管径{0}", num2);
						YJKMessageBox.Show(drivepipeFamilyName + " 没有" + str + " 的数据。");
					}
					else
					{
						num++;
					}
				}
				else
				{
					this.AddDrivepipeForPipe(uiApp, pipe, linkFiles, drivepipeDimMark);
				}
			}
			if (num > 0)
			{
				YJKMessageBox.Show(string.Format("有{0}根水管查询不到套管数据，不能加套管。", num));
			}
		}

		private void AddDrivepipeForPipe(UIApplication uiApp, Pipe pipe, List<LinkFile> fileList, string sMark)
		{
			Document document = uiApp.ActiveUIDocument.Document;
			this.DeleteDrivepipeOnPipe(document, pipe.Id);
			List<Wall> intersectWallByPipe = CmdTools.GetIntersectWallByPipe(pipe, document);
			foreach (LinkFile linkFile in fileList)
			{
				Document document2 = uiApp.Application.OpenDocumentFile(linkFile.FileName);
				if (document2 != null)
				{
					intersectWallByPipe.AddRange(CmdTools.GetIntersectWallByPipe(pipe, document2));
				}
			}
			Line line = CmdTools.FindPipeLine(pipe);
			XYZ direction = line.Direction;
			double dAngle = XYZ.BasisX.AngleOnPlaneTo(direction, XYZ.BasisZ);
			foreach (Wall wall in intersectWallByPipe)
			{
				if ((int)wall.WallType.Kind != 2 && (int)wall.WallType.Kind != 1 && !((wall.Location as LocationCurve).Curve.GetType() == typeof(Arc)) && Math.Abs(CmdTools.FindWallVector(wall).AngleTo(direction) - Math.PI*.5) <= 0.0001)
				{
					double dPipeDia = AssistFunc.mmToFeet(100.0);
					double width = wall.WallType.Width;
					foreach (XYZ ptPos in CmdTools.GetCvIntersect2WallPoints(line, wall))
					{
						ElementId elementId = this.InsertDrivepipe(document, ptPos, dPipeDia, width, dAngle, sMark);
						if (elementId != null)
						{
							Element element = document.GetElement(elementId);
							this.WritePipeIdToXData(element, pipe.Id);
						}
					}
				}
			}
		}

		private FamilySymbol LoadFamily(UIApplication uiApp, string strFamilyName)
		{
			return DbOpeningBase.LoadOpeningFamily(uiApp.ActiveUIDocument.Document, strFamilyName);
		}

		private ElementId InsertDrivepipe(Autodesk.Revit.DB.Document doc, XYZ ptPos, double dPipeDia, double dLength, double dAngle, string sMark)
		{
			Transaction transaction = new Transaction(doc, "InsertFamilySymbol");
			transaction.Start();
			try
			{
				UnifiedModified.ActivateFamilySymbol(this.m_Drivepipe);
				FamilyInstance familyInstance = doc.Create.NewFamilyInstance(ptPos, this.m_Drivepipe, doc.ActiveView);
				doc.Regenerate();
				familyInstance.GetParameter("墙厚度").Set(dLength);
				familyInstance.GetParameter("管宽度").Set(dPipeDia);
				familyInstance.GetParameter("总宽度").Set(dPipeDia + 0.5);
				Line line = YJKLineEx.YJKGetUnBound(ptPos, XYZ.BasisZ);
				ElementTransformUtils.RotateElement(doc, familyInstance.Id, line, dAngle);
				this.SetDrivepipeSharedPara(doc, familyInstance, AssistFunc.feetToMM(ptPos.Z) / 1000.0, sMark);
				this.m_lstAllDrivepipe.Add(familyInstance);
				transaction.Commit();
				return familyInstance.Id;
			}
			catch
			{
				transaction.RollBack();
			}
			return null;
		}

		private void DeleteDrivepipeOnPipe(Autodesk.Revit.DB.Document doc, ElementId pipeId)
		{
			Transaction transaction = new Transaction(doc, "DeleteInstance");
			transaction.Start();
			for (int i = 0; i < this.m_lstAllDrivepipe.Count; i++)
			{
				FamilyInstance familyInstance = this.m_lstAllDrivepipe[i];
				if (this.ReadPipeIdFromXData(familyInstance) == pipeId)
				{
					doc.Delete(familyInstance.Id);
					this.m_lstAllDrivepipe.Remove(familyInstance);
					i--;
				}
			}
			transaction.Commit();
		}

		private void SetDrivepipeSharedPara(Autodesk.Revit.DB.Document doc, FamilyInstance Drivepipe, double dElev, string sMark)
		{
			try
			{
                BuiltInCategory integerValue = (BuiltInCategory)Drivepipe.Category.Id.IntegerValue;
				Dictionary<string, ParameterType> dictionary = new Dictionary<string, ParameterType>();
				if (Drivepipe.GetParameter("标注标高") == null)
				{
                    dictionary.Add("标注标高", (ParameterType)1);
				}
				if (Drivepipe.GetParameter("标注内容") == null)
				{
                    dictionary.Add("标注内容", (ParameterType)1);
				}
				if (dictionary.Count > 0)
				{
					SharedParameter.InsertSharedParameter(doc, integerValue, "套管信息", dictionary, false, true);
				}
				Drivepipe.GetParameter("标注标高").Set(dElev.ToString("f3"));
				Drivepipe.GetParameter("标注内容").Set(sMark);
				doc.Regenerate();
			}
			catch
			{
			}
		}

		private string GetDrivepipeFamilyName(int nDrivepipeType)
		{
			if (nDrivepipeType == 0)
			{
				return "穿墙套管";
			}
			if (nDrivepipeType == 1)
			{
				return "柔性防水套管A";
			}
			if (nDrivepipeType == 2)
			{
				return "柔性防水套管B";
			}
			if (nDrivepipeType == 3)
			{
				return "刚性防水套管A";
			}
			if (nDrivepipeType == 4)
			{
				return "刚性防水套管B";
			}
			if (nDrivepipeType == 5)
			{
				return "刚性防水套管C";
			}
			if (nDrivepipeType == 6)
			{
				return "柔性密闭套管";
			}
			if (nDrivepipeType == 7)
			{
				return "刚性密闭套管";
			}
			return "穿墙套管";
		}

		private string GetDrivepipeDimName(string strFamilyName)
		{
			if (strFamilyName.Contains("穿墙套管"))
			{
				return "穿墙套管";
			}
			if (strFamilyName.Contains("防水套管"))
			{
				return "防水套管";
			}
			if (strFamilyName.Contains("密闭套管"))
			{
				return "密闭套管";
			}
			return "穿墙套管";
		}

		private string GetDrivepipeDimMark(string sFamilyName, int nPipeDia)
		{
			string text = "DN";
			if (sFamilyName.Contains("柔性防水套管"))
			{
				text = string.Format("D{0}", (int)(this.m_dimConfig.FlexWPDrivePipeDimType + 1));
			}
			else if (sFamilyName.Contains("刚性防水套管"))
			{
				text = string.Format("D{0}", (int)(this.m_dimConfig.InFlexWPDrivePipeDimType + 1));
			}
			else if (sFamilyName.Contains("柔性密闭套管"))
			{
				text = string.Format("D{0}", (int)(this.m_dimConfig.FlexSealDrivePipeDimType + 1));
			}
			else if (sFamilyName.Contains("刚性密闭套管"))
			{
				text = string.Format("D{0}", (int)(this.m_dimConfig.InFlexSealDrivePipeDimType + 1));
			}
			string text2 = this.ReadDrivepipeData(sFamilyName, nPipeDia, text);
			if (text2 == null)
			{
				return null;
			}
			if (sFamilyName == "穿墙套管")
			{
				return "φ" + text2;
			}
			return string.Concat(new string[]
			{
				this.GetDrivepipeDimName(sFamilyName),
				" ",
				text,
				" ",
				text2
			});
		}

		private string ReadDrivepipeData(string sFamilyName, int nPipeDia, string sAttribute)
		{
			string result;
			try
			{
				string str = string.Format("管径{0}", nPipeDia);
				result = this.m_xmlDoc.SelectSingleNode("Root/" + sFamilyName + "/" + str).Attributes[sAttribute].Value;
			}
			catch
			{
				result = null;
			}
			return result;
		}

		public ElementId ReadPipeIdFromXData(Element elem)
		{
			ElementId result = null;
			Guid guid = new Guid(CmdDrivepipeAdd.m_strXDataGuid);
			Schema schema = Schema.Lookup(guid);
			if (schema != null)
			{
				Entity entity = elem.GetEntity(schema);
				if (entity != null && entity.SchemaGUID == guid)
				{
					Field field = schema.GetField("AttachPipeId");
					result = new ElementId(entity.Get<int>(field));
				}
			}
			return result;
		}

		public void WritePipeIdToXData(Element elem, ElementId pipeId)
		{
			Transaction transaction = new Transaction(elem.Document, "WriteXData");
			transaction.Start();
			Guid guid = new Guid(CmdDrivepipeAdd.m_strXDataGuid);
			Schema schema = Schema.Lookup(guid);
			if (schema == null)
			{
				SchemaBuilder schemaBuilder = new SchemaBuilder(guid);
				schemaBuilder.SetSchemaName("DrivepipeXData");
				schemaBuilder.AddSimpleField("AttachPipeId", typeof(int));
				schema = schemaBuilder.Finish();
			}
			Entity entity = new Entity(schema);
			Field field = schema.GetField("AttachPipeId");
			entity.Set<int>(field, pipeId.IntegerValue);
			elem.SetEntity(entity);
			transaction.Commit();
		}

		private XmlDocument m_xmlDoc;

		private FamilySymbol m_Drivepipe;

		private List<FamilyInstance> m_lstAllDrivepipe;

		private ConfigDataOperate.OfferConfigData m_dimConfig;

		private static string m_strXDataGuid = "F38AC4F2-49E9-4FEC-8FF7-C9F949C3DF99";
	}
}
